/********************************************************************************
 * @file    app_mqtt.c
 * @brief   mqtt通讯应用逻辑处理
 * 
 * @author  nzttj
 * @date    2025-02-17
 * @version 1.0
 * 
 * Copyright (C) 2025 nzttj
 * 
 * 本软件使用 GNU 通用公共许可证 (GPL) 第 3 版授权。
 * 
 * 您可以自由使用、修改、分发本软件，但必须遵守以下条件：
 * 1. 源代码必须开放，且您修改后的代码也必须以 GPL 许可证发布。
 * 2. 发布或分发本软件时，必须附带本许可证，并提供源代码或获取源代码的方式。
 * 
 * 本软件按“原样”提供，不附带任何担保，使用风险由用户自行承担。
 * 
 ********************************************************************************/

#include "app_mqtt.h"
#include "hal_wifi.h"
#include "app_iot_ctrl.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mqtt_client.h"

#define MQTT_QOS (0)

static const char *TAG = "app_mqtt";
static TaskHandle_t s_mqtt_init_task_handle = NULL;
static app_mqtt_info_t s_mqtt_info = {
    .cfg = APP_MQTT_CFG_DEFAULT,
    .topic = APP_MQTT_TOPIC_DEFAULT,
};
static esp_mqtt_client_handle_t s_mqtt_client;

static void _generate_client_id(char *client_id)
{
    uint8_t mac[6];

    // 获取设备的MAC地址
    hal_wifi_get_mac(HAL_WIFI_IF_STA, mac);
    snprintf(client_id, sizeof(s_mqtt_info.cfg.client_id), "smart-socket-%02x%02x%02x%02x%02x%02x",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

static void _mqtt_connect_handler(esp_mqtt_event_handle_t event)
{
    if (strlen(s_mqtt_info.topic.set_topic) > 0)
    {
        esp_mqtt_client_subscribe(event->client, s_mqtt_info.topic.set_topic, MQTT_QOS);
    }
    if (strlen(s_mqtt_info.topic.report_topic) > 0)
    {
        esp_mqtt_client_subscribe(event->client, s_mqtt_info.topic.report_topic, MQTT_QOS);
    }
    if (strlen(s_mqtt_info.topic.ota_topic) > 0)
    {
        esp_mqtt_client_subscribe(event->client, s_mqtt_info.topic.ota_topic, MQTT_QOS);
    }

    s_mqtt_info.connected = true;
}

static void _mqtt_disconnect_handler(esp_mqtt_event_handle_t event)
{
    s_mqtt_info.connected = false;
}

static void _mqtt_message_handler(esp_mqtt_event_handle_t event)
{
    // printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
    // printf("DATA=%.*s\r\n", event->data_len, event->data);
    if (strstr(event->topic, s_mqtt_info.topic.set_topic) != NULL)
    {
        app_iot_ctrl_data_parse(event->data, event->data_len);
    }
    else if (strstr(event->topic, s_mqtt_info.topic.ota_topic) != NULL)
    {
        // printf("OTA TOPIC\r\n");
    }
}

static void _event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;

    switch (event->event_id)
    {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
        _mqtt_connect_handler(event);
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        _mqtt_disconnect_handler(event);
        break;
    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT_EVENT_DATA");
        _mqtt_message_handler(event);
        break;
    case MQTT_EVENT_ERROR:
        ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}

static void _mqtt_init_task(void *param)
{
    esp_mqtt_client_config_t mqtt_cfg = {
        .uri = s_mqtt_info.cfg.url,
        .client_id = s_mqtt_info.cfg.client_id,
    };

    if (strlen(s_mqtt_info.cfg.client_id) == 0)
    {
        _generate_client_id(s_mqtt_info.cfg.client_id);
    }
    if (strlen(s_mqtt_info.cfg.username) > 0)
    {
        mqtt_cfg.username = s_mqtt_info.cfg.username;
    }
    if (strlen(s_mqtt_info.cfg.password) > 0)
    {
        mqtt_cfg.password = s_mqtt_info.cfg.password;
    }

    s_mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(s_mqtt_client, ESP_EVENT_ANY_ID, _event_handler, NULL);
    esp_mqtt_client_start(s_mqtt_client);

    s_mqtt_init_task_handle = NULL;
    vTaskDelete(NULL);
}

int app_mqtt_init(void)
{
    if ((s_mqtt_init_task_handle != NULL) || (s_mqtt_client != NULL))
    {
        return 0;
    }

    return (xTaskCreate(_mqtt_init_task, "mqtt_init", 2048, NULL, 5, &s_mqtt_init_task_handle) == pdPASS) ? 0 : -1;
}

int app_mqtt_deinit(void)
{
    if (s_mqtt_client != NULL)
    {
        esp_mqtt_client_destroy(s_mqtt_client);
        s_mqtt_client = NULL;
    }

    return 0;
}

int app_mqtt_publish(const char *topic, const char *data, int len)
{
    if (s_mqtt_client == NULL || s_mqtt_info.connected == false)
    {
        return -1;
    }

    return esp_mqtt_client_publish(s_mqtt_client, topic, data, len, MQTT_QOS, 0);
}

int app_mqtt_data_report(const char *data, int len)
{
    return app_mqtt_publish((const char *)s_mqtt_info.topic.report_topic, data, len);
}

app_mqtt_info_t *app_mqtt_get_info(void)
{
    return &s_mqtt_info;
}
